﻿using Edu.Abstracts;
using Edu.Entitys;
using Edu.Utilities;
using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Application.Dtos;
using Volo.Abp.AutoMapper;
using Volo.Abp.Identity;

namespace Edu.Services
{
    public class LoginInDto
    {
        public string Code { get; set; }
    }

    public class RegisterInDto
    {
        [Required]
        public string PhoneNum { get; set; }
        [Required]
        public string Name { get; set; }
        [Required]
        public string WxName { get; set; }
        [Required]
        public string Avatar { get; set; }
        [Required]
        public string Code { get; set; }
    }
    [AutoMapFrom(typeof(AppUser))]
    public class WeChatUserDto : EntityDto<Guid>
    {

        public WeChatUserDto()
        {
            var date = DateTimeOffset.Now;
            this.Year = date.Year;
            this.Quarter = date.GetQuarter();
            var quarterEndDate = date.EndOfQuarter();
            this.QuarterEndDays = (quarterEndDate - date).Days;
        }

        public string Name { get; set; }

        public string PhoneNumber { get; set; }

        public string Area { get; set; }

        public IList<string> Roles { get; set; }

        public int Year { get; set; }

        public int Quarter { get; set; }

        public int QuarterEndDays { get; set; }

        public string Token { get; set; }
    }

    public class WeChatAccountService : WeChatAppServiceBase
    {
        private IWeChatClient _client;
        private IdentityUserManager _userManager;
        private IAppUserRepository _userRepository;
        private JWTOptions jwtOptions;

        public WeChatAccountService(
            IOptions<JWTOptions> options,
            IWeChatClient weChatClient,
            IdentityUserManager userManager,
             IAppUserRepository appUserRepository)
        {
            this._client = weChatClient;
            this._userManager = userManager;
            this._userRepository = appUserRepository;

            this.jwtOptions = options.Value;
        }

        /// <summary>
        ///
        /// </summary>
        /// <param name="code"></param>
        /// <param name="name">微信用户名称</param>
        /// <returns></returns>
        [AllowAnonymous]
        public async Task<WeChatUserDto> Login(LoginInDto loginInDto, string sid)
        {
            return new WeChatUserDto();

            (string openid, string sessionKey, string unionid, int errcode, string errmsg) = await this._client.code2Session(loginInDto.Code);

            if (errcode != 0)
            {
                throw new UserFriendlyException(errmsg);
            }

            var idenityUser = await _userManager.FindByLoginAsync(WeChatConstant.LoginProvider, openid);
            if (idenityUser == null)
            {
                return new WeChatUserDto();
            }

            var appUser = await _userRepository.GetAsync(idenityUser.Id);
            return await MapperUser(appUser, idenityUser);
        }

        [AllowAnonymous]
        public async Task<WeChatUserDto> Register(RegisterInDto registerInDto)
        {

            return await TestLogin(registerInDto.PhoneNum, registerInDto.Name);

            (string openid, string sessionKey, string unionid, int errcode, string errmsg) = await this._client.code2Session(registerInDto.Code);

            if (errcode != 0)
            {
                throw new UserFriendlyException(errmsg);
            }
            var user = await _userManager.FindByLoginAsync(WeChatConstant.LoginProvider, openid);

            if (user != null && (user.PhoneNumber != registerInDto.PhoneNum || user.Name != registerInDto.Name))
            {
                throw new UserFriendlyException("该微信号已经和其他账号绑定了,请重新登陆或联系管理员");
            }

            var appUser = _userRepository.FirstOrDefault(a => a.PhoneNumber == registerInDto.PhoneNum && a.Name == registerInDto.Name);
            if (appUser == null)
            {
                throw new UserFriendlyException("请确定你的手机号码和用户名正确");
            }
            appUser.Avatar = registerInDto.Avatar;
            appUser.WeChatName = registerInDto.WxName;
            await _userRepository.UpdateAsync(appUser, autoSave: true);

            if (user == null)
            {
                user = await _userManager.GetByIdAsync(appUser.Id);
                try
                {
                    var loginResult = await _userManager.AddLoginAsync(user, new Microsoft.AspNetCore.Identity.UserLoginInfo(WeChatConstant.LoginProvider, openid, registerInDto.WxName));
                    if (loginResult.Succeeded == false)
                    {
                        throw new UserFriendlyException("添加登录信息失败");
                    }
                }
                catch (Exception)
                {

                    throw new UserFriendlyException("该账号已经和他人的微信号绑定了,请重新登陆或联系管理员");
                }


            }
            return await MapperUser(appUser, user);
        }

        private async Task<WeChatUserDto> TestLogin(string PhoneNum, string name)
        {
            var appUser = _userRepository.FirstOrDefault(a => a.PhoneNumber == PhoneNum && a.Name == name);
            var idenityUser = await _userManager.GetByIdAsync(appUser.Id);

            return await MapperUser(appUser, idenityUser);
        }

        private async Task<WeChatUserDto> MapperUser(AppUser appUser, IdentityUser idenityUser)
        {
            var result = ObjectMapper.Map<AppUser, WeChatUserDto>(appUser);
            result.Area = EduConsts.AreaData[result.Area];
            result.Roles = await _userManager.GetRolesAsync(idenityUser);
            result.Token = GeneralJwtToken(appUser);
            return result;
        }


        private string GeneralJwtToken(AppUser user)
        {
            // authentication successful so generate jwt token
            var tokenHandler = new JwtSecurityTokenHandler();
            var key = Encoding.ASCII.GetBytes(jwtOptions.Secret);
            var tokenDescriptor = new SecurityTokenDescriptor
            {
                Subject = new ClaimsIdentity(new Claim[]
                {
                    new Claim(ClaimTypes.NameIdentifier, user.Id.ToString())
                }),
                Expires = DateTime.UtcNow.AddDays(7),
                SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
            };
            var token = tokenHandler.CreateToken(tokenDescriptor);
            return tokenHandler.WriteToken(token);
        }
    }
}
